﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

#nullable disable
namespace BeetleX.XRPC
{
    public class DelegatePublisher
    {
        private ConcurrentDictionary<long, ISession> mSessions = new ConcurrentDictionary<long, ISession>();
        private ISession[] Sessions = new ISession[0];

        public DelegatePublisher(string name) => this.Name = name;

        public string Name { get; set; }

        public Delegate Delegate { get; set; }

        public void Invoke<T>(T p1) => this.OnVoidExecute((object)p1);

        public void Invoke<T, T1>(T p1, T1 p2) => this.OnVoidExecute((object)p1, (object)p2);

        public void Invoke<T, T1, T2>(T p1, T1 p2, T2 p3)
        {
            this.OnVoidExecute((object)p1, (object)p2, (object)p3);
        }

        public void Invoke<T, T1, T2, T3>(T p1, T1 p2, T2 p3, T3 p4)
        {
            this.OnVoidExecute((object)p1, (object)p2, (object)p3, (object)p4);
        }

        public void Invoke<T, T1, T2, T3, T4>(T p1, T1 p2, T2 p3, T3 p4, T4 p5)
        {
            this.OnVoidExecute((object)p1, (object)p2, (object)p3, (object)p4, (object)p5);
        }

        public void Invoke<T, T1, T2, T3, T4, T5>(T p1, T1 p2, T2 p3, T3 p4, T4 p5, T5 p6)
        {
            this.OnVoidExecute((object)p1, (object)p2, (object)p3, (object)p4, (object)p5, (object)p6);
        }

        public void Invoke<T, T1, T2, T3, T4, T5, T6>(
          T p1,
          T1 p2,
          T2 p3,
          T3 p4,
          T4 p5,
          T5 p6,
          T6 p7)
        {
            this.OnVoidExecute((object)p1, (object)p2, (object)p3, (object)p4, (object)p5, (object)p6, (object)p7);
        }

        public void Invoke<T, T1, T2, T3, T4, T5, T6, T7>(
          T p1,
          T1 p2,
          T2 p3,
          T3 p4,
          T4 p5,
          T5 p6,
          T6 p7,
          T7 p8)
        {
            this.OnVoidExecute((object)p1, (object)p2, (object)p3, (object)p4, (object)p5, (object)p6, (object)p7, (object)p8);
        }

        public void Invoke<T, T1, T2, T3, T4, T5, T6, T7, T8>(
          T p1,
          T1 p2,
          T2 p3,
          T3 p4,
          T4 p5,
          T5 p6,
          T6 p7,
          T7 p8,
          T8 p9)
        {
            this.OnVoidExecute((object)p1, (object)p2, (object)p3, (object)p4, (object)p5, (object)p6, (object)p7, (object)p8, (object)p9);
        }

        public void Invoke<T, T1, T2, T3, T4, T5, T6, T7, T8, T9>(
          T p1,
          T1 p2,
          T2 p3,
          T3 p4,
          T4 p5,
          T5 p6,
          T6 p7,
          T7 p8,
          T8 p9,
          T9 p10)
        {
            this.OnVoidExecute((object)p1, (object)p2, (object)p3, (object)p4, (object)p5, (object)p6, (object)p7, (object)p8, (object)p9, (object)p10);
        }

        public MethodInfo GetMethod(string method, int parameters)
        {
            foreach (MethodInfo method1 in this.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public))
            {
                if (method1.GetParameters().Length == parameters && method1.Name.IndexOf(method) == 0)
                    return method1;
            }
            throw new XRPCException("Delegate proxy method not support!");
        }

        public void Add(ISession session)
        {
            this.mSessions[session.ID] = session;
            this.Sessions = this.mSessions.Values.ToArray<ISession>();
        }

        public void Remove(ISession session)
        {
            this.mSessions.TryRemove(session.ID, out ISession _);
            this.Sessions = this.mSessions.Values.ToArray<ISession>();
        }

        public Delegate CreateDelegate(Type type)
        {
            if ((object)this.Delegate == null)
            {
                List<Type> list = ((IEnumerable<ParameterInfo>)type.GetMethod("Invoke").GetParameters()).Select<ParameterInfo, Type>((Func<ParameterInfo, Type>)(a => a.ParameterType)).ToList<Type>();
                MethodInfo method1 = this.GetMethod("Invoke", list.Count);
                MethodInfo method2 = list.Count > 0 ? method1.MakeGenericMethod(list.ToArray()) : method1;
                this.Delegate = Delegate.CreateDelegate(type, (object)this, method2);
            }
            return this.Delegate;
        }

        protected virtual void OnVoidExecute(params object[] data)
        {
            using RPCPacket data1 = new RPCPacket();
            data1.NeedReply = false;
            data1.Url = "/__delegate/" + this.Name;
            data1.Data = data;
            foreach (ISession session in this.Sessions)
            {
                if (session.IsDisposed)
                    this.Remove(session);
                else
                    session.Send((object)data1);
            }
        }
    }
}
